package com.example.shuiyin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.shuiyin.dto.FileDto;
import com.example.shuiyin.dto.FileInfoDTO;
import com.example.shuiyin.dto.FileUploadResult;
import com.example.shuiyin.entity.FileInfo;
import com.example.shuiyin.exception.AppException;
import com.example.shuiyin.exception.ErrorCode;
import com.example.shuiyin.mapper.FileInfoMapper;
import com.example.shuiyin.service.FileService;
import com.example.shuiyin.service.MinioStorageService;
import com.example.shuiyin.service.QuotaService;
import com.example.shuiyin.service.StorageService;
import com.example.shuiyin.util.DtoConverters;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
public class FileServiceImpl implements FileService {

    private final FileInfoMapper fileInfoMapper;
    
    @Autowired
    private QuotaService quotaService;
    
    private final JdbcTemplate jdbcTemplate;
    
    @Autowired
    private MinioStorageService storageService;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    public FileServiceImpl(FileInfoMapper fileInfoMapper, 
                          JdbcTemplate jdbcTemplate) {
        this.fileInfoMapper = fileInfoMapper;
        this.jdbcTemplate = jdbcTemplate;
    }
    
    @Cacheable(value = "fileCache", key = "#fileId", unless = "#result == null")
    @Override
    public FileInfo getFileInfo(String fileId) {
        FileInfo fileInfo = fileInfoMapper.selectByFileId(fileId);
        if (fileInfo == null) {
            throw new AppException("文件不存在", ErrorCode.RESOURCE_NOT_FOUND);
        }
        return fileInfo;
    }
    
    @Transactional(rollbackFor = Exception.class)
    public FileUploadResult saveFile(Long userId, MultipartFile file, String type) {
        String fileName = file.getOriginalFilename();
        String fileExtension = getFileExtension(fileName);
        String contentType = file.getContentType();
        long fileSize = file.getSize();
        
        // 检查文件类型和大小
        validateFile(file, type);
        
        // 计算文件哈希，用于去重
        String fileHash = calculateMD5(file);
        
        // 查找是否有相同哈希的文件(仅针对同一用户)
        FileInfo existingFile = fileInfoMapper.selectByUserIdAndFileHashAndStatus(userId, fileHash, "ACTIVE");
        
        if (existingFile != null) {
            // 文件已存在，直接返回
            existingFile.setLastAccessTime(LocalDateTime.now());
            existingFile.setUpdatedAt(LocalDateTime.now());
            fileInfoMapper.updateById(existingFile);
            
            return FileUploadResult.builder()
                    .fileId(existingFile.getFileId())
                    .fileName(existingFile.getFileName())
                    .filePath(existingFile.getFilePath())
                    .fileSize(existingFile.getFileSize())
                    .contentType(existingFile.getContentType())
                    .duplicated(true)
                    .build();
        }
        
        // 生成存储路径
        String fileId = generateFileId();
        String objectName = generateObjectName(userId, type, fileId, fileExtension);
        
        try {
            // 上传到MinIO
            String filePath = storageService.uploadFile(file, objectName);
            
            // 保存文件信息到数据库
            FileInfo fileInfo = new FileInfo();
            fileInfo.setFileId(fileId);
            fileInfo.setUserId(userId);
            fileInfo.setFileName(fileName);
            fileInfo.setOriginalName(fileName);
            fileInfo.setFilePath(filePath);
            fileInfo.setFileSize(fileSize);
            fileInfo.setContentType(contentType);
            fileInfo.setStatus("ACTIVE");
            fileInfo.setUploadTime(LocalDateTime.now());
            fileInfo.setLastAccessTime(LocalDateTime.now());
            fileInfo.setUpdatedAt(LocalDateTime.now());
            fileInfo.setFileHash(fileHash);
            
            // 设置缩略图URL（如果是图片）
            if (contentType != null && contentType.startsWith("image/")) {
                fileInfo.setThumbnailUrl("/api/file/" + fileId + "/thumbnail");
            }
            
            fileInfoMapper.insert(fileInfo);
            
            // 更新用户存储配额
            quotaService.recordStorageUsage(userId, fileSize);
            
            return FileUploadResult.builder()
                    .fileId(fileId)
                    .fileName(fileName)
                    .filePath(filePath)
                    .fileSize(fileSize)
                    .contentType(contentType)
                    .duplicated(false)
                    .build();
        } catch (Exception e) {
            log.error("文件上传失败: {}", e.getMessage(), e);
            throw new AppException("文件上传失败: " + e.getMessage(), ErrorCode.FILE_UPLOAD_ERROR);
        }
    }
    
    @Override
    @Transactional
    public void saveFileInfo(FileInfo fileInfo) {
        if (fileInfo.getFileId() == null) {
            fileInfo.setFileId(generateFileId());
        }
        
        if (fileInfo.getUploadTime() == null) {
            fileInfo.setUploadTime(LocalDateTime.now());
        }
        
        if (fileInfo.getLastAccessTime() == null) {
            fileInfo.setLastAccessTime(LocalDateTime.now());
        }
        
        if (fileInfo.getStatus() == null) {
            fileInfo.setStatus("ACTIVE");
        }
        
        fileInfoMapper.insert(fileInfo);
        
        // 更新用户存储配额
        updateUserQuota(fileInfo.getUserId(), fileInfo.getFileSize(), true);
    }

    @Override
    public Page<FileDto> getUserFiles(Long userId, int page, int limit) {
        Page<FileInfo> filePage = new Page<>(page, limit);
        
        LambdaQueryWrapper<FileInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FileInfo::getUserId, userId)
                .eq(FileInfo::getStatus, "ACTIVE")
                .orderByDesc(FileInfo::getUploadTime);
        
        Page<FileInfo> result = fileInfoMapper.selectPage(filePage, queryWrapper);
        
        // 转换为DTO
        Page<FileDto> dtoPage = new Page<>(result.getCurrent(), result.getSize(), result.getTotal());
        dtoPage.setRecords(result.getRecords().stream()
                .map(fileInfo -> FileDto.builder()
                        .id(fileInfo.getId())
                        .fileId(fileInfo.getFileId())
                        .fileName(fileInfo.getFileName())
                        .contentType(fileInfo.getContentType())
                        .fileSize(fileInfo.getFileSize())
                        .status(fileInfo.getStatus())
                        .uploadTime(fileInfo.getUploadTime())
                        .deleteTime(fileInfo.getDeletedTime())
                        .url(fileInfo.getFilePath())
                        .thumbnailUrl(fileInfo.getThumbnailUrl())
                        .build())
                .collect(Collectors.toList()));
        
        return dtoPage;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = "fileCache", key = "#fileId")
    public boolean deleteFile(String fileId, Long userId) {
        FileInfo fileInfo = fileInfoMapper.selectByFileIdAndUserId(fileId, userId);
        if (fileInfo == null) {
            throw new AppException("文件不存在或无权限删除", ErrorCode.RESOURCE_NOT_FOUND);
        }
        
        try {
            // 从存储中删除文件
            storageService.deleteObject(fileInfo.getFilePath());
            
            // 更新文件状态
            fileInfo.setStatus("DELETED");
            fileInfo.setDeletedTime(LocalDateTime.now());
            fileInfoMapper.updateById(fileInfo);
            
            // 更新用户存储配额
            updateUserQuota(userId, fileInfo.getFileSize(), false);
            
            return true;
        } catch (Exception e) {
            log.error("删除文件失败: {}", e.getMessage(), e);
            throw new AppException("删除文件失败: " + e.getMessage(), ErrorCode.FILE_DELETE_ERROR);
        }
    }

    @Override
    public FileDto getFileById(String fileId, Long userId) {
        FileInfo fileInfo = fileInfoMapper.selectByFileIdAndUserId(fileId, userId);
        if (fileInfo == null) {
            throw new AppException("文件不存在或无权限访问", ErrorCode.RESOURCE_NOT_FOUND);
        }
        
        // 转换为FileDto
        return FileDto.builder()
                .id(fileInfo.getId())
                .fileId(fileInfo.getFileId())
                .fileName(fileInfo.getFileName())
                .contentType(fileInfo.getContentType())
                .fileSize(fileInfo.getFileSize())
                .status(fileInfo.getStatus())
                .uploadTime(fileInfo.getUploadTime())
                .deleteTime(fileInfo.getDeletedTime())
                .url(fileInfo.getFilePath())
                .thumbnailUrl(fileInfo.getThumbnailUrl())
                .build();
    }

    @Override
    @Transactional
    public boolean updateFileStatus(String fileId, String status, Long userId) {
        FileInfo fileInfo = fileInfoMapper.selectByFileIdAndUserId(fileId, userId);
        if (fileInfo == null) {
            throw new AppException("文件不存在或无权限访问", ErrorCode.RESOURCE_NOT_FOUND);
        }
        
        fileInfo.setStatus(status);
        
        if ("DELETED".equals(status) && fileInfo.getDeletedTime() == null) {
            fileInfo.setDeletedTime(LocalDateTime.now());
            
            // 如果是删除操作，更新用户配额
            updateUserQuota(userId, fileInfo.getFileSize(), false);
        }
        
        return fileInfoMapper.updateById(fileInfo) > 0;
    }

    @Override
    @Transactional
    public int cleanupTestFileMetadata(String prefix) {
        try {
            log.info("开始清理测试文件元数据，路径前缀: {}", prefix);
            
            // 获取要删除的文件列表
            List<FileInfo> filesToDelete = fileInfoMapper.selectByPathPrefix(prefix);
            log.info("找到{}个符合条件的文件", filesToDelete.size());
            
            // 从存储中删除文件
            for (FileInfo fileInfo : filesToDelete) {
                try {
                    storageService.deleteObject(fileInfo.getFilePath());
                    log.debug("已从存储中删除文件: {}", fileInfo.getFilePath());
                } catch (Exception e) {
                    log.warn("删除存储文件失败: {}, 错误: {}", fileInfo.getFilePath(), e.getMessage());
                }
                
                // 更新文件状态
                fileInfo.setStatus("DELETED");
                fileInfo.setDeletedTime(LocalDateTime.now());
                fileInfoMapper.updateById(fileInfo);
                
                // 更新用户配额
                updateUserQuota(fileInfo.getUserId(), fileInfo.getFileSize(), false);
            }
            
            // 删除数据库记录
            int count = fileInfoMapper.deleteByPathPrefix(prefix);
            log.info("成功清理{}个测试文件元数据", count);
            
            return count;
        } catch (Exception e) {
            log.error("清理测试文件元数据失败: {}", e.getMessage(), e);
            throw new AppException("清理测试文件元数据失败: " + e.getMessage(), ErrorCode.INTERNAL_ERROR);
        }
    }

    @Override
    @Transactional
    public void recalculateUserQuota(Long userId) {
        try {
            log.info("开始重新计算用户[{}]的存储配额", userId);
            
            // 计算用户总的文件大小
            Long totalSize = fileInfoMapper.selectTotalFileSize(userId);
            if (totalSize == null) {
                totalSize = 0L;
            }
            
            // 通过QuotaService更新用户配额
            quotaService.setStorageUsage(userId, totalSize);
            
            log.info("用户[{}]的存储配额已更新为: {}字节", userId, totalSize);
        } catch (Exception e) {
            log.error("重新计算用户配额失败: {}", e.getMessage(), e);
            throw new AppException("重新计算用户配额失败: " + e.getMessage(), ErrorCode.INTERNAL_ERROR);
        }
    }
    
    /**
     * 更新用户存储配额
     * @param userId 用户ID
     * @param fileSize 文件大小
     * @param isAdd 是否增加配额（true: 增加, false: 减少）
     */
    private void updateUserQuota(Long userId, Long fileSize, boolean isAdd) {
        try {
            if (isAdd) {
                quotaService.recordStorageUsage(userId, fileSize);
            } else {
                quotaService.reduceStorageUsage(userId, fileSize);
            }
        } catch (Exception e) {
            log.error("更新用户配额失败: {}", e.getMessage(), e);
            // 不抛出异常，避免影响主要流程
        }
    }
    
    /**
     * 增加用户存储配额的辅助方法
     */
    private void updateUserQuota(Long userId, Long fileSize) {
        updateUserQuota(userId, fileSize, true);
    }
    
    /**
     * 将实体转换为DTO
     */
    @Override
    public FileInfoDTO convertToDto(FileInfo fileInfo) {
        if (fileInfo == null) {
            return null;
        }
        
        return FileInfoDTO.builder()
                .id(fileInfo.getId())
                .fileId(fileInfo.getFileId())
                .fileName(fileInfo.getFileName())
                .originalName(fileInfo.getOriginalName())
                .contentType(fileInfo.getContentType())
                .fileSize(fileInfo.getFileSize())
                .filePath(fileInfo.getFilePath())
                .url(fileInfo.getUrl())
                .thumbnailUrl(fileInfo.getThumbnailUrl())
                .status(fileInfo.getStatus())
                .userId(fileInfo.getUserId())
                .uploadTime(fileInfo.getUploadTime())
                .lastAccessTime(fileInfo.getLastAccessTime())
                .updatedAt(fileInfo.getUpdatedAt())
                .build();
    }
    
    /**
     * 生成文件ID
     */
    private String generateFileId() {
        return UUID.randomUUID().toString().replace("-", "");
    }
    
    /**
     * 生成对象名称
     */
    private String generateObjectName(Long userId, String type, String fileId, String extension) {
        return String.format("%s/%d/%s%s", 
                type, userId, fileId, extension.isEmpty() ? "" : "." + extension);
    }
    
    /**
     * 计算文件MD5
     */
    private String calculateMD5(MultipartFile file) {
        try (InputStream is = file.getInputStream()) {
            return DigestUtils.md5DigestAsHex(is);
        } catch (IOException e) {
            log.error("计算文件MD5失败: {}", e.getMessage(), e);
            return UUID.randomUUID().toString(); // 降级策略
        }
    }
    
    /**
     * 验证文件
     */
    private void validateFile(MultipartFile file, String type) {
        if (file.isEmpty()) {
            throw new AppException("文件不能为空", ErrorCode.INVALID_PARAMETER);
        }
        
        String fileName = file.getOriginalFilename();
        String contentType = file.getContentType();
        long fileSize = file.getSize();
        
        // 文件名安全检查
        if (fileName != null && (fileName.contains("../") || fileName.contains("..\\"))) {
            throw new AppException("文件名不合法", ErrorCode.INVALID_PARAMETER);
        }
        
        // 白名单内容类型检查
        if (contentType == null || !isAllowedContentType(contentType, type)) {
            throw new AppException("不支持的文件类型", ErrorCode.UNSUPPORTED_FILE_TYPE);
        }
        
        // 大小检查
        if ("image".equals(type) && fileSize > 10 * 1024 * 1024) {
            throw new AppException("图片大小超过限制(10MB)", ErrorCode.FILE_TOO_LARGE);
        } else if ("document".equals(type) && fileSize > 20 * 1024 * 1024) {
            throw new AppException("文档大小超过限制(20MB)", ErrorCode.FILE_TOO_LARGE);
        } else if (fileSize > 50 * 1024 * 1024) {
            throw new AppException("文件大小超过限制(50MB)", ErrorCode.FILE_TOO_LARGE);
        }
    }
    
    /**
     * 检查内容类型是否在允许列表中
     */
    private boolean isAllowedContentType(String contentType, String type) {
        if ("image".equals(type)) {
            return contentType.startsWith("image/");
        } else if ("document".equals(type)) {
            return contentType.equals("application/pdf") ||
                   contentType.equals("application/msword") ||
                   contentType.equals("application/vnd.openxmlformats-officedocument.wordprocessingml.document") ||
                   contentType.equals("application/vnd.ms-excel") ||
                   contentType.equals("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") ||
                   contentType.equals("text/plain");
        } else if ("video".equals(type)) {
            return contentType.startsWith("video/");
        } else {
            // 其他类型的默认允许列表
            return !contentType.contains("script") && 
                   !contentType.contains("shell") &&
                   !contentType.contains("executable");
        }
    }
    
    /**
     * 获取文件扩展名
     */
    private String getFileExtension(String filename) {
        if (filename == null || filename.isEmpty() || !filename.contains(".")) {
            return "";
        }
        return filename.substring(filename.lastIndexOf(".") + 1);
    }

    @Override
    @Transactional
    public int batchDeleteFiles(List<String> fileIds, Long userId) {
        if (fileIds == null || fileIds.isEmpty()) {
            return 0;
        }
        
        int count = 0;
        for (String fileId : fileIds) {
            try {
                deleteFile(fileId, userId);
                count++;
            } catch (Exception e) {
                log.error("删除文件失败: {}, 错误: {}", fileId, e.getMessage(), e);
                // 继续处理其他文件
            }
        }
        
        return count;
    }

    @Override
    @Transactional
    public int cleanupOldFiles(int days) {
        if (days <= 0) {
            throw new AppException("天数必须大于0", ErrorCode.INVALID_PARAMETER);
        }
        
        LocalDateTime cutoffDate = LocalDateTime.now().minusDays(days);
        
        // 获取要删除的文件列表
        List<FileInfo> filesToDelete = fileInfoMapper.selectExpiredFiles(cutoffDate);
        
        int count = 0;
        for (FileInfo fileInfo : filesToDelete) {
            try {
                // 从存储中删除文件
                storageService.deleteObject(fileInfo.getFilePath());
                
                // 更新文件状态
                fileInfo.setStatus("DELETED");
                fileInfo.setDeletedTime(LocalDateTime.now());
                fileInfoMapper.updateById(fileInfo);
                
                // 更新用户存储配额
                updateUserQuota(fileInfo.getUserId(), fileInfo.getFileSize(), false);
                
                count++;
            } catch (Exception e) {
                log.error("清理过期文件失败: {}", e.getMessage(), e);
            }
        }
        
        return count;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public FileInfoDTO uploadFile(MultipartFile file, String type, Long userId) throws IOException {
        String lockKey = "user_quota_lock:" + userId;
        boolean locked = false;
        
        try {
            // 尝试获取锁，防止并发更新配额
            locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 30, TimeUnit.SECONDS);
            if (!locked) {
                throw new AppException("系统繁忙，请稍后再试", ErrorCode.SERVICE_UNAVAILABLE);
            }
            
            // 检查文件类型和大小
            validateFile(file, type);
            
            // 检查用户配额
            validateQuota(userId, file.getSize());
            
            // 文件上传逻辑
            String fileName = file.getOriginalFilename();
            String fileExtension = getFileExtension(fileName);
            String contentType = file.getContentType();
            long fileSize = file.getSize();
            
            // 计算文件哈希，用于去重
            String fileHash = calculateMD5(file);
            
            // 查找是否有相同哈希的文件(仅针对同一用户)
            FileInfo existingFile = fileInfoMapper.selectByUserIdAndFileHashAndStatus(userId, fileHash, "ACTIVE");
            
            if (existingFile != null) {
                // 文件已存在，直接返回
                existingFile.setLastAccessTime(LocalDateTime.now());
                existingFile.setUpdatedAt(LocalDateTime.now());
                fileInfoMapper.updateById(existingFile);
                
                return convertToDto(existingFile);
            }
            
            // 生成存储路径
            String fileId = generateFileId();
            String objectName = generateObjectName(userId, type, fileId, fileExtension);
            
            // 上传到MinIO
            String filePath = storageService.uploadFile(file, objectName);
            
            // 保存文件信息到数据库
            FileInfo fileInfo = new FileInfo();
            fileInfo.setFileId(fileId);
            fileInfo.setUserId(userId);
            fileInfo.setFileName(fileName);
            fileInfo.setOriginalName(fileName);
            fileInfo.setFilePath(filePath);
            fileInfo.setFileSize(fileSize);
            fileInfo.setContentType(contentType);
            fileInfo.setStatus("ACTIVE");
            fileInfo.setUploadTime(LocalDateTime.now());
            fileInfo.setLastAccessTime(LocalDateTime.now());
            fileInfo.setUpdatedAt(LocalDateTime.now());
            fileInfo.setFileHash(fileHash);
            
            // 设置缩略图URL（如果是图片）
            if (contentType != null && contentType.startsWith("image/")) {
                fileInfo.setThumbnailUrl("/api/file/" + fileId + "/thumbnail");
            }
            
            fileInfoMapper.insert(fileInfo);
            
            // 更新用户存储配额
            updateUserQuota(userId, fileSize, true);
            
            return convertToDto(fileInfo);
        } catch (Exception e) {
            log.error("文件上传失败: {}", e.getMessage(), e);
            throw new AppException("文件上传失败: " + e.getMessage(), ErrorCode.FILE_UPLOAD_ERROR);
        } finally {
            // 确保锁被释放
            if (locked) {
                redisTemplate.delete(lockKey);
            }
        }
    }

    /**
     * 验证用户配额是否足够
     */
    private void validateQuota(Long userId, Long fileSize) {
        // 获取用户当前使用量和限额
        Long currentUsage = quotaService.getStorageUsage(userId);
        Long quota = quotaService.getStorageQuota(userId);
        
        // 检查是否超出配额
        if (currentUsage + fileSize > quota) {
            throw new AppException(
                String.format("存储空间不足，当前已使用 %.2f MB，上限 %.2f MB", 
                    currentUsage / (1024.0 * 1024.0), 
                    quota / (1024.0 * 1024.0)),
                ErrorCode.STORAGE_QUOTA_EXCEEDED
            );
        }
    }

    // 实现listFiles方法
    @Override
    public List<FileInfoDTO> listFiles(Long userId, String status, int pageNum, int pageSize) {
        Page<FileInfo> pageObj = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<FileInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FileInfo::getUserId, userId);
        if (status != null && !status.isEmpty()) {
            wrapper.eq(FileInfo::getStatus, status);
        }
        wrapper.orderByDesc(FileInfo::getUploadTime);
        
        Page<FileInfo> result = fileInfoMapper.selectPage(pageObj, wrapper);
        return result.getRecords().stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
    }

    /**
     * 验证文件的所有权
     * 
     * @param fileId 文件ID
     * @param userId 用户ID
     * @throws AppException 如果用户不是文件的拥有者，抛出FORBIDDEN异常
     */
    @Override
    public void verifyFileOwnership(String fileId, Long userId) {
        if (fileId == null || fileId.isEmpty()) {
            throw new AppException("文件ID不能为空", ErrorCode.INVALID_PARAMETER);
        }
        if (userId == null) {
            throw new AppException("用户ID不能为空", ErrorCode.INVALID_PARAMETER);
        }
        
        // 查询文件信息
        FileInfo fileInfo = fileInfoMapper.selectByFileId(fileId);
        if (fileInfo == null) {
            throw new AppException("文件不存在", ErrorCode.FILE_NOT_FOUND);
        }
        
        // 验证所有权
        if (!fileInfo.getUserId().equals(userId)) {
            log.warn("用户[{}]尝试访问不属于他的文件[{}]", userId, fileId);
            throw new AppException("您没有权限访问此文件", ErrorCode.FORBIDDEN);
        }
    }

    /**
     * 将文件标记为已删除
     * 
     * @param fileId 文件ID
     * @param userId 用户ID
     * @return 是否标记成功
     */
    @Override
    public boolean markAsDeleted(String fileId, Long userId) {
        try {
            // 检查参数
            if (fileId == null || fileId.isEmpty()) {
                throw new AppException("文件ID不能为空", ErrorCode.INVALID_PARAMETER);
            }
            
            // 检查文件是否存在且属于当前用户
            FileInfo fileInfo = fileInfoMapper.selectByFileIdAndUserId(fileId, userId);
            if (fileInfo == null) {
                return false;
            }
            
            // 标记为已删除
            fileInfo.setStatus("DELETED");
            fileInfo.setDeletedTime(LocalDateTime.now());
            
            // 更新数据库
            int rows = fileInfoMapper.updateById(fileInfo);
            return rows > 0;
        } catch (Exception e) {
            log.error("标记文件为已删除失败: {}", e.getMessage(), e);
            if (e instanceof AppException) {
                throw e;
            }
            throw new AppException("标记文件为已删除失败", ErrorCode.INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 检查用户存储空间是否足够
     */
    @Override
    public boolean checkStorageSpace(Long userId, long fileSize) {
        try {
            // 获取用户存储使用量和配额
            long usedSpace = quotaService.getStorageUsage(userId);
            long quota = quotaService.getStorageQuota(userId);
            
            // 检查是否超过配额
            return (usedSpace + fileSize) <= quota;
        } catch (Exception e) {
            log.error("检查存储空间失败: {}", e.getMessage(), e);
            return false;
        }
    }
} 